home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_200
/
283_03
/
macros.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-12-01
|
8KB
|
387 lines
/* macros.c -- 11/27/88, d.c.oshel */
#include <stdarg.h>
#include "burlap.h"
extern FORM_RULES burlap[];
static char *token;
static char *slop;
static char *moreslop;
jmp_buf osiris;
static int crash_macro( char *msg,... )
{
va_list arg_ptr;
char buffer[128];
va_start( arg_ptr, msg );
vsprintf( buffer, msg, arg_ptr );
va_end( arg_ptr );
boxmsg( buffer );
longjmp( osiris,-1 );
}
static int valid_number( char *p )
{
static char test[] = "0123456789-.,$+";
for ( ; *p; p++ )
{
if ( strchr( test, *p ) == NULL )
return (0);
}
return (1);
}
static int numeric_args( char * a1, char * a2 )
{
return ( valid_number( a1 ) && valid_number( a2 ) );
}
static long number( char *p )
{
long n, sign;
for ( n = 0L, sign = 1L; *p; p++ )
{
if ( *p == '-' )
sign = -1L;
else if ( isdigit(*p) )
{
n *= 10L;
n += (long) (*p - '0');
}
}
n *= sign;
return ( n );
}
/* load_and_compare() --
this function determines N from the first field in q,
then moves the contents of field N to token,
then move the string argument which immediately follows in q to moreslop,
then returns the result of case-insensitive comparison between the two
*/
static int load_and_compare( char *q, char *op )
{
int k, j, n, len;
char *p;
memset(token,0,MACROSIZE);
memset(moreslop,0,MACROSIZE);
/* numeric argument refers to a burlap field */
if (*q)
{
for( ; *q && !(isdigit(*q) || *q == '-'); q++ )
;
for ( n = 0; *q && (isdigit(*q) || *q == '-'); q++ )
{
if (*q == '-')
;
else
{
n *= 10;
n += (*q - '0');
}
}
/* index array on base 0, and do range check */
n -= 1;
if ( n < 0 || n > ISAM_field_range ) /* 0 <= n <= NUMBER_OF_REAL_FIELDS */
n = ISAM_field_range;
len = burlap[n].len;
if (len < 0)
len = MAXVFLDLEN;
p = *(burlap[n].fptr);
memcpy( token, p, len );
strip_blanks( token );
strlwr(token);
}
/* string argument might be quoted */
if (*q)
{
for( ++q; *q && *q == ' '; q++ )
;
if (*q)
{
if (*q == APOSTROPHE || *q == QUOTE)
k = *q++; /* delimiter */
else
k = EOL;
for ( j = 0; *q && *q != k; q++, j++ )
*(moreslop + j) = *q;
strip_blanks( moreslop );
strlwr( moreslop );
}
}
return (strcmp( token, moreslop ));
}
/*====================== Recursive Macro Expansions ======================*/
int expand_macros( char *buffer )
{
char *p, *q; /* RECURSIVE */
char /* **r, *str, */ *tkn;
static int i, arg1, arg2, sign;
/* RECURSIVE, but macros expand by inserting in place, so the
receiving buffer is not adversely affected by nested macros,
and there is NO undue stress on the stack! There is no
error checking, but the working buffers are huge, so there is
no problem with almost any practical expansion.
In the burlap version, all of the defined macros "expand" to
shorter, not longer, strings.
*/
if ( (p = strstr( buffer, "(" )) != NULL )
{
if ( strstr( p + 1, "(" ) != NULL )
{
expand_macros( p + 1 ); /* RECURSIVE */
}
q = p; /* mark opening paren */
i = 0;
while (*p)
{
if (*p == '(') /* skip over "quoted macros" embedded in arg */
++i;
else if (*p == ')')
--i;
if ( !i )
break;
else
p++;
}
if ( *p != ')' )
crash_macro("macro needs ')': %s", q );
*q = '\0'; /* wipes out opening paren */
*p = '\0'; /* wipes out closing paren and delimits macro */
++p; /* advance beyond macro to next portion of buffer */
/* ===== Arithmetic and Logical Operators ===== */
if ((i = *( q + 1 )) == '&' ||
i == '|' ||
i == '^'
)
{
tkn = q + 1;
for( q += 2; *q && !(isdigit(*q) || *q == '-'); q++ )
;
for ( sign = 1, arg1 = 0; *q && (isdigit(*q) || *q == '-'); q++ )
{
if (*q == '-')
sign = -1;
else
{
arg1 *= 10;
arg1 += (*q - '0');
}
}
arg1 *= sign;
for( ++q; *q && !(isdigit(*q) || *q == '-'); q++ )
;
for ( sign = 1, arg2 = 0; *q && (isdigit(*q) || *q == '-'); q++ )
{
if (*q == '-')
sign = -1;
else
{
arg2 *= 10;
arg2 += (*q - '0');
}
}
arg2 *= sign;
switch (i)
{
case '&': arg1 = (arg1 != 0)? 1: 0;
arg2 = (arg2 != 0)? 1: 0;
arg1 &= arg2;
break;
case '|': arg1 = (arg1 != 0)? 1: 0;
arg2 = (arg2 != 0)? 1: 0;
arg1 |= arg2;
break;
case '^': arg1 = (arg1 != 0)? 1: 0;
arg1 ^= 1;
break;
}
sprintf( slop, "%d", arg1 );
}
/* ===== Conditionals ===== */
else if ( strncmp( q + 1, "<=", 2 ) == 0 )
{
i = load_and_compare(q+1,"<=");
if ( numeric_args( token, moreslop ) )
{
arg1 = number(token);
arg2 = number(moreslop);
i = ( arg1 < arg2 || arg1 == arg2 )? 1: 0;
}
else
i = ( i <= 0 )? 1: 0;
sprintf( slop, "%d", i );
}
else if ( strncmp( q + 1, ">=", 2 ) == 0 )
{
i = load_and_compare(q+1,">=");
if ( numeric_args( token, moreslop ) )
{
arg1 = number(token);
arg2 = number(moreslop);
i = ( arg1 > arg2 || arg1 == arg2 )? 1: 0;
}
else
i = ( i >= 0 )? 1: 0;
sprintf( slop, "%d", i );
}
else if ( strncmp( q + 1, "<", 1 ) == 0 )
{
i = load_and_compare(q+1,"<");
if ( numeric_args( token, moreslop ) )
{
arg1 = number(token);
arg2 = number(moreslop);
i = ( arg1 < arg2 )? 1: 0;
}
else
i = ( i < 0 )? 1: 0;
sprintf( slop, "%d", i );
}
else if ( strncmp( q + 1, ">", 1 ) == 0 )
{
i = load_and_compare(q+1,">");
if ( numeric_args( token, moreslop ) )
{
arg1 = number(token);
arg2 = number(moreslop);
i = ( arg1 > arg2 )? 1: 0;
}
else
i = ( i > 0 )? 1: 0;
sprintf( slop, "%d", i );
}
else if ( strncmp( q + 1, "=", 1 ) == 0 )
{
i = load_and_compare(q+1,"=");
if ( numeric_args( token, moreslop ) )
{
arg1 = number(token);
arg2 = number(moreslop);
i = ( arg1 == arg2 )? 1: 0;
}
else
i = ( i == 0 )? 1: 0;
sprintf( slop, "%d", i );
}
else if ( strncmp( q + 1, "?", 1 ) == 0 )
{
load_and_compare(q+1,"?"); /* sets token and moreslop */
if ( strlen(token) && strlen(moreslop) )
tkn = strstr( token, moreslop );
else
tkn = NULL;
i = ( tkn != NULL )? 1 : 0;
sprintf( slop, "%d", i );
}
else if ( stricmp( q+1, "TRUE" ) == 0 )
{
strcpy( slop,"1");
}
else if ( stricmp( q+1, "FALSE" ) == 0 )
{
strcpy( slop,"0");
}
else if ( stricmp( q+1, "T" ) == 0 )
{
strcpy( slop,"1");
}
else if ( stricmp( q+1, "F" ) == 0 )
{
strcpy( slop,"0");
}
else
{
strcpy(slop,"1"); /* any (undefined) is 1 */
}
/* insert macro expansion into receiving buffer */
q = "macro buffer overflow"; /* insertion error message */
strcpy( moreslop, buffer );
if (((strlen(moreslop) + strlen(slop))) >= (MACROSIZE - 1))
crash_macro(q);
else
strcat( moreslop, slop );
if (((strlen(moreslop) + strlen(p))) >= (MACROSIZE - 1))
crash_macro(q);
else
strcat( moreslop, p );
strcpy( buffer, moreslop );
/* clear working buffers */
memset( moreslop, 0, MACROSIZE );
memset( slop, 0, MACROSIZE );
}
}
/* macro evaluation returns 1 or 0, or -1 if syntax error */
int evaluate_macro( char *p )
{
int result;
token = malloc( MACROSIZE );
slop = malloc( MACROSIZE );
moreslop = malloc( MACROSIZE );
if ( token == (char *)NULL || slop == (char *)NULL || moreslop == (char *)NULL )
bomb("out of memory");
if ( setjmp( os